package com.tosh;

import com.tosh.exception.ExceptionFastDI;
import com.tosh.model.Bean;
import com.tosh.model.ConstructorArg;
import com.tosh.model.Property;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

import static com.tosh.Utils.capitalize;
import static com.tosh.Utils.isNOE;

/**
 * User: arsentyev
 * Date: 06.08.12
 */
public class ResolverFastDI {
    public static void fillByInstances(List<Bean> beans, Map<String, Object> beansMap) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException {
        for(Bean bean: beans) {
            Object obj = getInstance1(bean);
            beansMap.put(bean.getId(), obj);
        }
    }

    public static void resolveDependencies(List<Bean> beans, Map<String, Object> beansMap) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        for(Bean bean : beans) {
            List<Property> properties = bean.getProperties();
            Object o1 = null, o2 = null;

            if (isNOE(properties)) {
                o1 = beansMap.get(bean.getId());

                for (Property property : properties) {
                    o2 = beansMap.get(property.getRefId());

                    Method m = o1.getClass().getMethod("set" + capitalize(property.getName()), o2.getClass());
                    m.invoke(o1, o2);
                }
            }
        }
    }

    private static Object getInstance(Bean bean) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        if(bean == null || isNOE(bean.getClazz())) {
            throw new ExceptionFastDI("Does not provided class name.");
        }

        return Class.forName(bean.getClazz()).newInstance();
    }

    private static Object getInstance1(Bean bean) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {
        if(bean == null || isNOE(bean.getClazz())) {
            throw new ExceptionFastDI("Does not provided class name.");
        }
        List<ConstructorArg> args = bean.getConstructorArgs();

        if(isNOE(args)) {
            return Class.forName(bean.getClazz()).newInstance();
        }

        int size = args.size();

        Class clazz = Class.forName(bean.getClazz());
        Constructor[] constructors = clazz.getConstructors();

        for(Constructor constructor : constructors) {
            Class[] classes = constructor.getParameterTypes();

//            if(isNOE(types)) {
//                throw new ExceptionFastDI("Where is no such constructor.");
//            }

            if(size == classes.length) {
                Object[] zz = getObjects(classes, args);
                if(zz != null) {
                    return constructor.newInstance(zz);
                }
            }
        }
        throw new ExceptionFastDI("Where is no such constructor.");
//        return null;
    }

    private static Object[] getObjects(Class[] classes, List<ConstructorArg> args) {
        int i = 0;
        Class clazz = null;
        Object[] objects = new Object[classes.length];

        try {
            for(ConstructorArg arg: args) {
                clazz = classes[i];
                if(clazz.getName().equals("int") || clazz.getName().equals("Integer")) {
                    objects[i] = Integer.valueOf(arg.getValue());
                } else if(clazz.getName().equals("long") || clazz.getName().equals("Long")) {
                    objects[i] = Long.valueOf(arg.getValue());
                }
            }
        } catch (NumberFormatException ex) {
            return null;
        }

        return objects;
    }
}